import 'package:jiffy/jiffy.dart';

import '../pb/quote/EnKLine.pbenum.dart';
import '../pb/quote/KLine.pb.dart';

class KLineUtil {
  // static KLineEntity klineToKLineEntity(EnKLine enKLine, KLine kline) {
  //   KLineEntity klineEntity = KLineEntity.fromCustom(
  //       open: kline.open, high: kline.high, low: kline.low, close: kline.close, vol: 0, startTime: getKLineEntityStartTime(enKLine, kline.time.toInt() * 1000), endTime: getKLineEntityEndTime(enKLine, kline.time.toInt() * 1000));
  //   return klineEntity;
  // }

  // static KLineEntity tickToKLineEntity(EnKLine enKLine, Tick tick) {
  //   KLineEntity klineEntity = KLineEntity.fromCustom(open: tick.openPrice, high: tick.highestPrice, low: tick.lowestPrice, close: tick.last, vol: 0, startTime: tick.time.toInt() * 1000, endTime: getKLineEntityEndTime(enKLine, tick.time.toInt() * 1000));
  //   print(klineEntity);
  //   return klineEntity;
  // }
  
  static int getKLineEntityEndTime(EnKLine enKLine, int time) {
    Jiffy startTime = Jiffy.parseFromMillisecondsSinceEpoch(getKLineEntityStartTime(enKLine, time));
    Jiffy endTime = startTime;
    switch (enKLine) {
      case EnKLine.K_LINE_TYPE_15MIN:
        endTime = startTime.add(minutes: 15);
        break;
      case EnKLine.K_LINE_TYPE_1MIN:
        endTime = startTime.add(minutes: 1);
        break;
      case EnKLine.K_LINE_TYPE_2MIN:
        endTime = startTime.add(minutes: 2);
        break;
      case EnKLine.K_LINE_TYPE_30MIN:
        endTime = startTime.add(minutes: 30);
        break;
      case EnKLine.K_LINE_TYPE_3MIN:
        endTime = startTime.add(minutes: 3);
        break;
      case EnKLine.K_LINE_TYPE_5MIN:
        endTime = startTime.add(minutes: 5);
        break;
      case EnKLine.K_LINE_TYPE_60MIN:
        endTime = startTime.add(hours: 1);
        break;
      case EnKLine.K_LINE_TYPE_DAY:
        endTime = startTime.add(days: 1);
        break;
      case EnKLine.K_LINE_TYPE_MONTH:
        endTime = startTime.add(months: 1);
        break;
      case EnKLine.K_LINE_TYPE_UNKNOWN:
        // TODO: Handle this case.
        break;
      case EnKLine.K_LINE_TYPE_WEEK:
        endTime = startTime.add(weeks: 1);
        break;
      case EnKLine.K_LINE_TYPE_YEAR:
        endTime = startTime.add(years: 1);
        break;
    }
    return endTime.millisecondsSinceEpoch - 1;
  }

  static int getKLineEntityStartTime(EnKLine enKLine, int millisecondsSinceEpoch) {
    DateTime klineTime = DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch);
    DateTime startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, klineTime.minute);
    switch (enKLine) {
      case EnKLine.K_LINE_TYPE_15MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, (klineTime.minute ~/ 15) * 15);
        break;
      case EnKLine.K_LINE_TYPE_1MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, klineTime.minute);
        break;
      case EnKLine.K_LINE_TYPE_2MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, (klineTime.minute ~/ 2) * 2);
        break;
      case EnKLine.K_LINE_TYPE_30MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, (klineTime.minute ~/ 30) * 30);
        break;
      case EnKLine.K_LINE_TYPE_3MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, (klineTime.minute ~/ 3) * 3);
        break;
      case EnKLine.K_LINE_TYPE_5MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour, (klineTime.minute ~/ 5) * 5);
        break;
      case EnKLine.K_LINE_TYPE_60MIN:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day, klineTime.hour);
        break;
      case EnKLine.K_LINE_TYPE_DAY:
        startTime = DateTime(klineTime.year, klineTime.month, klineTime.day);
        break;
      case EnKLine.K_LINE_TYPE_MONTH:
        startTime = DateTime(klineTime.year, klineTime.month);
        break;
      case EnKLine.K_LINE_TYPE_UNKNOWN:
        startTime = klineTime;
        break;
      case EnKLine.K_LINE_TYPE_WEEK:
        Jiffy jiffy = Jiffy.parseFromDateTime(klineTime);
        int weeks = jiffy.weekOfYear;
        jiffy = Jiffy.parseFromDateTime(DateTime(klineTime.year, 1, 1));
        jiffy = jiffy.add(weeks: weeks - 1);
        startTime = jiffy.dateTime;
        break;
      case EnKLine.K_LINE_TYPE_YEAR:
        startTime = DateTime(klineTime.year);
        break;
    }
    return startTime.millisecondsSinceEpoch;
  }
  
  static int getQueryKlineNum(EnKLine enKLine, bool first){
    int result = 0;
    switch (enKLine) {
      case EnKLine.K_LINE_TYPE_1MIN:
        if (first) {
          result = 7200;
        } else {
          result = 60;
        }
        break;
      case EnKLine.K_LINE_TYPE_2MIN:
        if (first) {
          result = 3600;
        } else {
          result = 30;
        }
        break;
      case EnKLine.K_LINE_TYPE_3MIN:
        if (first) {
          result = 2400;
        } else {
          result = 20;
        }
        break;
      case EnKLine.K_LINE_TYPE_5MIN:
        if (first) {
          result = 1440;
        } else {
          result = 12;
        }
        break;
      case EnKLine.K_LINE_TYPE_15MIN:
        if (first) {
          result = 480;
        } else {
          result = 12;
        }
        break;
      case EnKLine.K_LINE_TYPE_30MIN:
        if (first) {
          result = 240;
        } else {
          result = 6;
        }
        break;
      case EnKLine.K_LINE_TYPE_60MIN:
        if (first) {
          result = 120;
        } else {
          result = 6;
        }
        break;
      case EnKLine.K_LINE_TYPE_DAY:
        if (first) {
          result = 366;
        } else {
          result = 6;
        }
        break;
      case EnKLine.K_LINE_TYPE_MONTH:
        if (first) {
          result = 36;
        } else {
          result = 6;
        }
        break;
      case EnKLine.K_LINE_TYPE_WEEK:
        if (first) {
          result = 53;
        } else {
          result = 6;
        }
        break;
    }
    return result;
  }

  static int getKLineSeconds(EnKLine enKLine){
    int now = DateTime.now().millisecondsSinceEpoch;
    int startTime = getKLineEntityStartTime(enKLine, now);
    int endTime = getKLineEntityEndTime(enKLine, now) + 1;
    return (endTime - startTime)~/1000;
  }

  static int getKLineRemainingSeconds(EnKLine enKLine, DateTime dateTime){
    int now = dateTime.millisecondsSinceEpoch;
    int endTime = getKLineEntityEndTime(enKLine, now);
    return (endTime - now)~/1000;
  }

  static void sortKLineListAscByTime(List<KLine> klineList) {
    klineList.sort((a, b) => a.time.compareTo(b.time));
  }

  static void sortKLineLisDescByTime(List<KLine> klineList) {
    klineList.sort((a, b) => b.time.compareTo(a.time));
  }
}
